﻿#region Using

using System.Collections.Generic;

using Common.Base;

using GameLogic.External;

#endregion

namespace GameLogic.Internal
{

    #region Using

    #endregion

    internal class Tile : GameEntity, ITile
    {
        private readonly RemovableQueue<Route> farmerRoutingQueue;

        private readonly RemovableQueue<Route> militiaRoutingQueue;

        private Building building;

        private int hitPoints;

        public Tile()
        {
            this.building = new FreeSpace(this);
            this.hitPoints = this.Settings.NeutralTileHitPoints;
            this.militiaRoutingQueue = new RemovableQueue<Route>();
            this.farmerRoutingQueue = new RemovableQueue<Route>();
            this.Owner = Player.NeutralPlayer;
            this.Position = new Position(0, 0);
        }

        internal Player Owner { get; private set; }

        public IBuilding Building
        {
            get
            {
                return this.building;
            }
        }

        public IEnumerable<IRoute> FarmerRoutes
        {
            get
            {
                return this.farmerRoutingQueue.ToList();
            }
        }

        public int Hitpoints
        {
            get
            {
                return this.hitPoints;
            }
        }

        public IEnumerable<IRoute> MilitiaRoutes
        {
            get
            {
                return this.militiaRoutingQueue.ToList();
            }
        }

        IPlayer ITile.Owner
        {
            get
            {
                return this.Owner;
            }
        }

        public Position Position { get; set; }

        public void Update(GameTime elapsedTime)
        {
            this.building.Update(elapsedTime);
        }

        internal void Receive(Militia militia)
        {
            if (!militia.Owner.Equals(this.Owner))
            {
                this.hitPoints -= this.Settings.MilitiaDamage;

                if (this.hitPoints <= 0)
                {
                    this.ChangeOwner(militia.Owner);
                }
            }
            else
            {
                if (this.hitPoints < Settings.PlayerTileHitPoints)
                {
                    this.hitPoints = this.hitPoints + Settings.MilitiaHealing;
                }
                else
                {
                    if (this.militiaRoutingQueue.Count > 0)
                    {
                        var nextRoute = this.militiaRoutingQueue.Dequeue();

                        nextRoute.Receive(militia);

                        this.militiaRoutingQueue.Enqueue(nextRoute);
                    }
                }
            }
        }

        internal void Receive(Farmer farmer)
        {
            if (farmer.Owner.Equals(this.Owner))
            {
                if (this.building.BuildingType == BuildingType.None || this.building.BuildingType == BuildingType.Castle)
                {
                    if (this.farmerRoutingQueue.Count != 0)
                    {
                        var nextRoute = this.farmerRoutingQueue.Dequeue();

                        nextRoute.Receive(farmer);

                        this.farmerRoutingQueue.Enqueue(nextRoute);
                    }
                }
                else
                {
                    this.building.TakeFarmer(farmer);
                }
            }
        }

        internal Result AddFarmerRoute(Route route)
        {
            if (this.farmerRoutingQueue.Count > 2)
            {
                return Result.Failure("You can only have 3 routes from a tile!");
            }

            if (this.farmerRoutingQueue.Contains(route))
            {
                return Result.Failure("You can not add a route a second times!");
            }

            this.farmerRoutingQueue.Enqueue(route);

            return Result.Success;
        }

        internal Result RemoveFarmerRoute(Route route)
        {
            if (!this.farmerRoutingQueue.Contains(route))
            {
                return Result.Failure("Route not found in the tile!");
            }

            this.farmerRoutingQueue.Remove(route);
            return Result.Success;
        }

        internal Result AddMilitiaRoute(Route route)
        {
            if (this.militiaRoutingQueue.Count > 2)
            {
                return Result.Failure("You can only have 3 routes from a tile!");
            }

            if (this.militiaRoutingQueue.Contains(route))
            {
                return Result.Failure("You can not add a route a second times!");
            }

            this.militiaRoutingQueue.Enqueue(route);

            return Result.Success;
        }

        internal Result RemoveMilitiaRoute(Route route)
        {
            if (!this.militiaRoutingQueue.Contains(route))
            {
                return Result.Failure("Route not found in the tile!");
            }

            this.militiaRoutingQueue.Remove(route);
            return Result.Success;
        }

        internal void DeclareAsStartingTileFor(Player player)
        {
            this.Owner = player;
            this.hitPoints = this.Settings.PlayerTileHitPoints;
            this.building = new Castle(this);
        }

        internal Result RaiseBuilding(BuildingType type)
        {
            if (this.building.BuildingType != BuildingType.None)
            {
                return Result.Failure("There is already a bulding on this tile!");
            }

            switch (type)
            {
                case BuildingType.Barrack:
                    this.building = new Barrack(this);
                    break;

                case BuildingType.GoldMine:
                    this.building = new GoldMine(this);
                    break;

                case BuildingType.ResearchLab:
                    this.building = new ResearchLab(this);
                    break;
            }

            return Result.Success;
        }

        internal bool ContainsMilitiaRoute(Route route)
        {
            return this.militiaRoutingQueue.Contains(route);
        }

        internal bool ContainsFarmerRoute(Route route)
        {
            return this.farmerRoutingQueue.Contains(route);
        }

        internal void ChangeOwner(Player owner)
        {
            this.Owner = owner;
            if (owner.Equals(Player.NeutralPlayer))
            {
                this.hitPoints = this.Settings.NeutralTileHitPoints;
            }
            else
            {
                this.hitPoints = this.Settings.PlayerTileHitPoints;
            }
            this.farmerRoutingQueue.Clear();
            this.militiaRoutingQueue.Clear();
            this.building.Reset();
        }
    }
}